/*
 * File   : mac_xgmii.v
 * Date   : 20150902
 * Author : Bibo Yang, ash_riple@hotmail.com
 *
 */

`timescale 1ns/1ns
module mac_xgmii(
  input  wire         rst,

  input  wire         xgmii_rx_clk,
  input  wire [71: 0] xgmii_rx_dc,
  output wire         xgmii_tx_clk,
  output reg  [71: 0] xgmii_tx_dc,

  (* mark_debug = "true" *) output reg          rx_vld,
  (* mark_debug = "true" *) output reg          rx_sop,
  (* mark_debug = "true" *) output reg          rx_eop,
  (* mark_debug = "true" *) output reg  [ 2: 0] rx_mod,
  (* mark_debug = "true" *) output reg  [63: 0] rx_dat,
  (* mark_debug = "true" *) input  wire         tx_vld,
  (* mark_debug = "true" *) input  wire         tx_sop,
  (* mark_debug = "true" *) input  wire         tx_eop,
  (* mark_debug = "true" *) input  wire [ 2: 0] tx_mod,
  (* mark_debug = "true" *) input  wire [63: 0] tx_dat
);

///////////////////////////////////////
// loopback XGMII clock
assign xgmii_tx_clk = xgmii_rx_clk;
//assign xgmii_tx_dc  = xgmii_rx_dc;


///////////////////////////////////////
// RGMII TX
///////////////////////////////////////

///////////////////////////////////////
// buffer interface signals
reg         int_tx_vld;
reg         int_tx_sop;
reg         int_tx_eop;
reg [ 2: 0] int_tx_mod;
reg [63: 0] int_tx_dat;
always @(posedge xgmii_rx_clk or posedge rst) begin
  if (rst) begin
    int_tx_vld <=  1'b0;
    int_tx_sop <=  1'b0;
    int_tx_eop <=  1'b0;
    int_tx_mod <=  3'd0;
    int_tx_dat <= 64'd0;
  end
  else begin
    int_tx_vld <= tx_vld;
    int_tx_sop <= tx_sop;
    int_tx_eop <= tx_eop;
    int_tx_mod <= tx_mod;
    int_tx_dat <= tx_dat;
  end
end
reg         int_tx_vld_d1;
reg         int_tx_sop_d1;
reg         int_tx_eop_d1;
reg [ 2: 0] int_tx_mod_d1;
reg [63: 0] int_tx_dat_d1;
always @(posedge xgmii_rx_clk or posedge rst) begin
  if (rst) begin
    int_tx_vld_d1 <=  1'b0;
    int_tx_sop_d1 <=  1'b0;
    int_tx_eop_d1 <=  1'b0;
    int_tx_mod_d1 <=  3'd0;
    int_tx_dat_d1 <= 64'd0;
  end
  else begin
    int_tx_vld_d1 <= int_tx_vld;
    int_tx_sop_d1 <= int_tx_sop;
    int_tx_eop_d1 <= int_tx_eop;
    int_tx_mod_d1 <= int_tx_mod;
    int_tx_dat_d1 <= int_tx_dat;
  end
end
reg         int_tx_vld_d2;
reg         int_tx_sop_d2;
reg         int_tx_eop_d2;
reg [ 2: 0] int_tx_mod_d2;
reg [63: 0] int_tx_dat_d2;
always @(posedge xgmii_rx_clk or posedge rst) begin
  if (rst) begin
    int_tx_vld_d2 <=  1'b0;
    int_tx_sop_d2 <=  1'b0;
    int_tx_eop_d2 <=  1'b0;
    int_tx_mod_d2 <=  3'd0;
    int_tx_dat_d2 <= 64'd0;
  end
  else begin
    int_tx_vld_d2 <= int_tx_vld_d1;
    int_tx_sop_d2 <= int_tx_sop_d1;
    int_tx_eop_d2 <= int_tx_eop_d1;
    int_tx_mod_d2 <= int_tx_mod_d1;
    int_tx_dat_d2 <= int_tx_dat_d1;
  end
end

// get non-aligned xgmii data and ctrl
(* mark_debug = "true" *) reg       xgmii_tx_ctrl7;
(* mark_debug = "true" *) reg [7:0] xgmii_tx_byte7;
(* mark_debug = "true" *) reg       xgmii_tx_ctrl6;
(* mark_debug = "true" *) reg [7:0] xgmii_tx_byte6;
(* mark_debug = "true" *) reg       xgmii_tx_ctrl5;
(* mark_debug = "true" *) reg [7:0] xgmii_tx_byte5;
(* mark_debug = "true" *) reg       xgmii_tx_ctrl4;
(* mark_debug = "true" *) reg [7:0] xgmii_tx_byte4;

(* mark_debug = "true" *) reg       xgmii_tx_ctrl3;
(* mark_debug = "true" *) reg [7:0] xgmii_tx_byte3;
(* mark_debug = "true" *) reg       xgmii_tx_ctrl2;
(* mark_debug = "true" *) reg [7:0] xgmii_tx_byte2;
(* mark_debug = "true" *) reg       xgmii_tx_ctrl1;
(* mark_debug = "true" *) reg [7:0] xgmii_tx_byte1;
(* mark_debug = "true" *) reg       xgmii_tx_ctrl0;
(* mark_debug = "true" *) reg [7:0] xgmii_tx_byte0;
always @(posedge xgmii_rx_clk or posedge rst) begin
  if (rst) begin
    {xgmii_tx_ctrl7, xgmii_tx_byte7} <= {9'h107};
    {xgmii_tx_ctrl6, xgmii_tx_byte6} <= {9'h107};
    {xgmii_tx_ctrl5, xgmii_tx_byte5} <= {9'h107};
    {xgmii_tx_ctrl4, xgmii_tx_byte4} <= {9'h107};
    {xgmii_tx_ctrl3, xgmii_tx_byte3} <= {9'h107};
    {xgmii_tx_ctrl2, xgmii_tx_byte2} <= {9'h107};
    {xgmii_tx_ctrl1, xgmii_tx_byte1} <= {9'h107};
    {xgmii_tx_ctrl0, xgmii_tx_byte0} <= {9'h107};
  end
  else if (int_tx_vld && int_tx_sop) begin
    {xgmii_tx_ctrl7, xgmii_tx_byte7} <= {9'h0d5};
    {xgmii_tx_ctrl6, xgmii_tx_byte6} <= {9'h055};
    {xgmii_tx_ctrl5, xgmii_tx_byte5} <= {9'h055};
    {xgmii_tx_ctrl4, xgmii_tx_byte4} <= {9'h055};
    {xgmii_tx_ctrl3, xgmii_tx_byte3} <= {9'h055};
    {xgmii_tx_ctrl2, xgmii_tx_byte2} <= {9'h055};
    {xgmii_tx_ctrl1, xgmii_tx_byte1} <= {9'h055};
    {xgmii_tx_ctrl0, xgmii_tx_byte0} <= {9'h1fb};
  end
  else if (int_tx_vld_d1 && int_tx_eop_d1) begin
    case (int_tx_mod_d1) 
      3'd1: begin
            {xgmii_tx_ctrl7, xgmii_tx_byte7} <= {9'h107};
            {xgmii_tx_ctrl6, xgmii_tx_byte6} <= {9'h107};
            {xgmii_tx_ctrl5, xgmii_tx_byte5} <= {9'h107};
            {xgmii_tx_ctrl4, xgmii_tx_byte4} <= {9'h107};
            {xgmii_tx_ctrl3, xgmii_tx_byte3} <= {9'h107};
            {xgmii_tx_ctrl2, xgmii_tx_byte2} <= {9'h107};
            {xgmii_tx_ctrl1, xgmii_tx_byte1} <= {9'h1fd};
            {xgmii_tx_ctrl0, xgmii_tx_byte0} <= {1'b0, int_tx_dat_d1[63:56]};
      end
      3'd2: begin
            {xgmii_tx_ctrl7, xgmii_tx_byte7} <= {9'h107};
            {xgmii_tx_ctrl6, xgmii_tx_byte6} <= {9'h107};
            {xgmii_tx_ctrl5, xgmii_tx_byte5} <= {9'h107};
            {xgmii_tx_ctrl4, xgmii_tx_byte4} <= {9'h107};
            {xgmii_tx_ctrl3, xgmii_tx_byte3} <= {9'h107};
            {xgmii_tx_ctrl2, xgmii_tx_byte2} <= {9'h1fd};
            {xgmii_tx_ctrl1, xgmii_tx_byte1} <= {1'b0, int_tx_dat_d1[55:48]};
            {xgmii_tx_ctrl0, xgmii_tx_byte0} <= {1'b0, int_tx_dat_d1[63:56]};
      end
      3'd3: begin
            {xgmii_tx_ctrl7, xgmii_tx_byte7} <= {9'h107};
            {xgmii_tx_ctrl6, xgmii_tx_byte6} <= {9'h107};
            {xgmii_tx_ctrl5, xgmii_tx_byte5} <= {9'h107};
            {xgmii_tx_ctrl4, xgmii_tx_byte4} <= {9'h107};
            {xgmii_tx_ctrl3, xgmii_tx_byte3} <= {9'h1fd};
            {xgmii_tx_ctrl2, xgmii_tx_byte2} <= {1'b0, int_tx_dat_d1[47:40]};
            {xgmii_tx_ctrl1, xgmii_tx_byte1} <= {1'b0, int_tx_dat_d1[55:48]};
            {xgmii_tx_ctrl0, xgmii_tx_byte0} <= {1'b0, int_tx_dat_d1[63:56]};
      end
      3'd4: begin
            {xgmii_tx_ctrl7, xgmii_tx_byte7} <= {9'h107};
            {xgmii_tx_ctrl6, xgmii_tx_byte6} <= {9'h107};
            {xgmii_tx_ctrl5, xgmii_tx_byte5} <= {9'h107};
            {xgmii_tx_ctrl4, xgmii_tx_byte4} <= {9'h1fd};
            {xgmii_tx_ctrl3, xgmii_tx_byte3} <= {1'b0, int_tx_dat_d1[39:32]};
            {xgmii_tx_ctrl2, xgmii_tx_byte2} <= {1'b0, int_tx_dat_d1[47:40]};
            {xgmii_tx_ctrl1, xgmii_tx_byte1} <= {1'b0, int_tx_dat_d1[55:48]};
            {xgmii_tx_ctrl0, xgmii_tx_byte0} <= {1'b0, int_tx_dat_d1[63:56]};
      end
      3'd5: begin
            {xgmii_tx_ctrl7, xgmii_tx_byte7} <= {9'h107};
            {xgmii_tx_ctrl6, xgmii_tx_byte6} <= {9'h107};
            {xgmii_tx_ctrl5, xgmii_tx_byte5} <= {9'h1fd};
            {xgmii_tx_ctrl4, xgmii_tx_byte4} <= {1'b0, int_tx_dat_d1[31:24]};
            {xgmii_tx_ctrl3, xgmii_tx_byte3} <= {1'b0, int_tx_dat_d1[39:32]};
            {xgmii_tx_ctrl2, xgmii_tx_byte2} <= {1'b0, int_tx_dat_d1[47:40]};
            {xgmii_tx_ctrl1, xgmii_tx_byte1} <= {1'b0, int_tx_dat_d1[55:48]};
            {xgmii_tx_ctrl0, xgmii_tx_byte0} <= {1'b0, int_tx_dat_d1[63:56]};
      end
      3'd6: begin
            {xgmii_tx_ctrl7, xgmii_tx_byte7} <= {9'h107};
            {xgmii_tx_ctrl6, xgmii_tx_byte6} <= {9'h1fd};
            {xgmii_tx_ctrl5, xgmii_tx_byte5} <= {1'b0, int_tx_dat_d1[23:16]};
            {xgmii_tx_ctrl4, xgmii_tx_byte4} <= {1'b0, int_tx_dat_d1[31:24]};
            {xgmii_tx_ctrl3, xgmii_tx_byte3} <= {1'b0, int_tx_dat_d1[39:32]};
            {xgmii_tx_ctrl2, xgmii_tx_byte2} <= {1'b0, int_tx_dat_d1[47:40]};
            {xgmii_tx_ctrl1, xgmii_tx_byte1} <= {1'b0, int_tx_dat_d1[55:48]};
            {xgmii_tx_ctrl0, xgmii_tx_byte0} <= {1'b0, int_tx_dat_d1[63:56]};
      end
      3'd7: begin
            {xgmii_tx_ctrl7, xgmii_tx_byte7} <= {9'h1fd};
            {xgmii_tx_ctrl6, xgmii_tx_byte6} <= {1'b0, int_tx_dat_d1[15: 8]};
            {xgmii_tx_ctrl5, xgmii_tx_byte5} <= {1'b0, int_tx_dat_d1[23:16]};
            {xgmii_tx_ctrl4, xgmii_tx_byte4} <= {1'b0, int_tx_dat_d1[31:24]};
            {xgmii_tx_ctrl3, xgmii_tx_byte3} <= {1'b0, int_tx_dat_d1[39:32]};
            {xgmii_tx_ctrl2, xgmii_tx_byte2} <= {1'b0, int_tx_dat_d1[47:40]};
            {xgmii_tx_ctrl1, xgmii_tx_byte1} <= {1'b0, int_tx_dat_d1[55:48]};
            {xgmii_tx_ctrl0, xgmii_tx_byte0} <= {1'b0, int_tx_dat_d1[63:56]};
      end
      3'd0: begin
            {xgmii_tx_ctrl7, xgmii_tx_byte7} <= {1'b0, int_tx_dat_d1[ 7: 0]};
            {xgmii_tx_ctrl6, xgmii_tx_byte6} <= {1'b0, int_tx_dat_d1[15: 8]};
            {xgmii_tx_ctrl5, xgmii_tx_byte5} <= {1'b0, int_tx_dat_d1[23:16]};
            {xgmii_tx_ctrl4, xgmii_tx_byte4} <= {1'b0, int_tx_dat_d1[31:24]};
            {xgmii_tx_ctrl3, xgmii_tx_byte3} <= {1'b0, int_tx_dat_d1[39:32]};
            {xgmii_tx_ctrl2, xgmii_tx_byte2} <= {1'b0, int_tx_dat_d1[47:40]};
            {xgmii_tx_ctrl1, xgmii_tx_byte1} <= {1'b0, int_tx_dat_d1[55:48]};
            {xgmii_tx_ctrl0, xgmii_tx_byte0} <= {1'b0, int_tx_dat_d1[63:56]};
      end
    endcase
  end
  else if (int_tx_vld_d2 && int_tx_eop_d2 && int_tx_mod_d2 == 3'd0) begin
    {xgmii_tx_ctrl7, xgmii_tx_byte7} <= {9'h107};
    {xgmii_tx_ctrl6, xgmii_tx_byte6} <= {9'h107};
    {xgmii_tx_ctrl5, xgmii_tx_byte5} <= {9'h107};
    {xgmii_tx_ctrl4, xgmii_tx_byte4} <= {9'h107};
    {xgmii_tx_ctrl3, xgmii_tx_byte3} <= {9'h107};
    {xgmii_tx_ctrl2, xgmii_tx_byte2} <= {9'h107};
    {xgmii_tx_ctrl1, xgmii_tx_byte1} <= {9'h107};
    {xgmii_tx_ctrl0, xgmii_tx_byte0} <= {9'h1fd};
  end
  else if (int_tx_vld_d2 && int_tx_eop_d2 && int_tx_mod_d2 != 3'd0) begin
    {xgmii_tx_ctrl7, xgmii_tx_byte7} <= {9'h107};
    {xgmii_tx_ctrl6, xgmii_tx_byte6} <= {9'h107};
    {xgmii_tx_ctrl5, xgmii_tx_byte5} <= {9'h107};
    {xgmii_tx_ctrl4, xgmii_tx_byte4} <= {9'h107};
    {xgmii_tx_ctrl3, xgmii_tx_byte3} <= {9'h107};
    {xgmii_tx_ctrl2, xgmii_tx_byte2} <= {9'h107};
    {xgmii_tx_ctrl1, xgmii_tx_byte1} <= {9'h107};
    {xgmii_tx_ctrl0, xgmii_tx_byte0} <= {9'h107};
  end
  else if (int_tx_vld_d1) begin
    {xgmii_tx_ctrl7, xgmii_tx_byte7} <= {1'b0, int_tx_dat_d1[ 7: 0]};
    {xgmii_tx_ctrl6, xgmii_tx_byte6} <= {1'b0, int_tx_dat_d1[15: 8]};
    {xgmii_tx_ctrl5, xgmii_tx_byte5} <= {1'b0, int_tx_dat_d1[23:16]};
    {xgmii_tx_ctrl4, xgmii_tx_byte4} <= {1'b0, int_tx_dat_d1[31:24]};
    {xgmii_tx_ctrl3, xgmii_tx_byte3} <= {1'b0, int_tx_dat_d1[39:32]};
    {xgmii_tx_ctrl2, xgmii_tx_byte2} <= {1'b0, int_tx_dat_d1[47:40]};
    {xgmii_tx_ctrl1, xgmii_tx_byte1} <= {1'b0, int_tx_dat_d1[55:48]};
    {xgmii_tx_ctrl0, xgmii_tx_byte0} <= {1'b0, int_tx_dat_d1[63:56]};
  end
  else begin
    {xgmii_tx_ctrl7, xgmii_tx_byte7} <= {9'h107};
    {xgmii_tx_ctrl6, xgmii_tx_byte6} <= {9'h107};
    {xgmii_tx_ctrl5, xgmii_tx_byte5} <= {9'h107};
    {xgmii_tx_ctrl4, xgmii_tx_byte4} <= {9'h107};
    {xgmii_tx_ctrl3, xgmii_tx_byte3} <= {9'h107};
    {xgmii_tx_ctrl2, xgmii_tx_byte2} <= {9'h107};
    {xgmii_tx_ctrl1, xgmii_tx_byte1} <= {9'h107};
    {xgmii_tx_ctrl0, xgmii_tx_byte0} <= {9'h107};
  end
end

// get non-aligned delayed xgmii data and ctrl
reg       xgmii_tx_ctrl7_d1, xgmii_tx_ctrl7_d2, xgmii_tx_ctrl7_d3;
reg [7:0] xgmii_tx_byte7_d1, xgmii_tx_byte7_d2, xgmii_tx_byte7_d3;
reg       xgmii_tx_ctrl6_d1, xgmii_tx_ctrl6_d2, xgmii_tx_ctrl6_d3;
reg [7:0] xgmii_tx_byte6_d1, xgmii_tx_byte6_d2, xgmii_tx_byte6_d3;
reg       xgmii_tx_ctrl5_d1, xgmii_tx_ctrl5_d2, xgmii_tx_ctrl5_d3;
reg [7:0] xgmii_tx_byte5_d1, xgmii_tx_byte5_d2, xgmii_tx_byte5_d3;
reg       xgmii_tx_ctrl4_d1, xgmii_tx_ctrl4_d2, xgmii_tx_ctrl4_d3;
reg [7:0] xgmii_tx_byte4_d1, xgmii_tx_byte4_d2, xgmii_tx_byte4_d3;
reg       xgmii_tx_ctrl3_d1, xgmii_tx_ctrl3_d2, xgmii_tx_ctrl3_d3;
reg [7:0] xgmii_tx_byte3_d1, xgmii_tx_byte3_d2, xgmii_tx_byte3_d3;
reg       xgmii_tx_ctrl2_d1, xgmii_tx_ctrl2_d2, xgmii_tx_ctrl2_d3;
reg [7:0] xgmii_tx_byte2_d1, xgmii_tx_byte2_d2, xgmii_tx_byte2_d3;
reg       xgmii_tx_ctrl1_d1, xgmii_tx_ctrl1_d2, xgmii_tx_ctrl1_d3;
reg [7:0] xgmii_tx_byte1_d1, xgmii_tx_byte1_d2, xgmii_tx_byte1_d3;
reg       xgmii_tx_ctrl0_d1, xgmii_tx_ctrl0_d2, xgmii_tx_ctrl0_d3;
reg [7:0] xgmii_tx_byte0_d1, xgmii_tx_byte0_d2, xgmii_tx_byte0_d3;
always @(posedge xgmii_rx_clk) begin
  {xgmii_tx_ctrl7_d1, xgmii_tx_byte7_d1} <= {xgmii_tx_ctrl7   , xgmii_tx_byte7   };
  {xgmii_tx_ctrl6_d1, xgmii_tx_byte6_d1} <= {xgmii_tx_ctrl6   , xgmii_tx_byte6   };
  {xgmii_tx_ctrl5_d1, xgmii_tx_byte5_d1} <= {xgmii_tx_ctrl5   , xgmii_tx_byte5   };
  {xgmii_tx_ctrl4_d1, xgmii_tx_byte4_d1} <= {xgmii_tx_ctrl4   , xgmii_tx_byte4   };
  {xgmii_tx_ctrl3_d1, xgmii_tx_byte3_d1} <= {xgmii_tx_ctrl3   , xgmii_tx_byte3   };
  {xgmii_tx_ctrl2_d1, xgmii_tx_byte2_d1} <= {xgmii_tx_ctrl2   , xgmii_tx_byte2   };
  {xgmii_tx_ctrl1_d1, xgmii_tx_byte1_d1} <= {xgmii_tx_ctrl1   , xgmii_tx_byte1   };
  {xgmii_tx_ctrl0_d1, xgmii_tx_byte0_d1} <= {xgmii_tx_ctrl0   , xgmii_tx_byte0   };

  {xgmii_tx_ctrl7_d2, xgmii_tx_byte7_d2} <= {xgmii_tx_ctrl7_d1, xgmii_tx_byte7_d1};
  {xgmii_tx_ctrl6_d2, xgmii_tx_byte6_d2} <= {xgmii_tx_ctrl6_d1, xgmii_tx_byte6_d1};
  {xgmii_tx_ctrl5_d2, xgmii_tx_byte5_d2} <= {xgmii_tx_ctrl5_d1, xgmii_tx_byte5_d1};
  {xgmii_tx_ctrl4_d2, xgmii_tx_byte4_d2} <= {xgmii_tx_ctrl4_d1, xgmii_tx_byte4_d1};
  {xgmii_tx_ctrl3_d2, xgmii_tx_byte3_d2} <= {xgmii_tx_ctrl3_d1, xgmii_tx_byte3_d1};
  {xgmii_tx_ctrl2_d2, xgmii_tx_byte2_d2} <= {xgmii_tx_ctrl2_d1, xgmii_tx_byte2_d1};
  {xgmii_tx_ctrl1_d2, xgmii_tx_byte1_d2} <= {xgmii_tx_ctrl1_d1, xgmii_tx_byte1_d1};
  {xgmii_tx_ctrl0_d2, xgmii_tx_byte0_d2} <= {xgmii_tx_ctrl0_d1, xgmii_tx_byte0_d1};

  {xgmii_tx_ctrl7_d3, xgmii_tx_byte7_d3} <= {xgmii_tx_ctrl7_d2, xgmii_tx_byte7_d2};
  {xgmii_tx_ctrl6_d3, xgmii_tx_byte6_d3} <= {xgmii_tx_ctrl6_d2, xgmii_tx_byte6_d2};
  {xgmii_tx_ctrl5_d3, xgmii_tx_byte5_d3} <= {xgmii_tx_ctrl5_d2, xgmii_tx_byte5_d2};
  {xgmii_tx_ctrl4_d3, xgmii_tx_byte4_d3} <= {xgmii_tx_ctrl4_d2, xgmii_tx_byte4_d2};
  {xgmii_tx_ctrl3_d3, xgmii_tx_byte3_d3} <= {xgmii_tx_ctrl3_d2, xgmii_tx_byte3_d2};
  {xgmii_tx_ctrl2_d3, xgmii_tx_byte2_d3} <= {xgmii_tx_ctrl2_d2, xgmii_tx_byte2_d2};
  {xgmii_tx_ctrl1_d3, xgmii_tx_byte1_d3} <= {xgmii_tx_ctrl1_d2, xgmii_tx_byte1_d2};
  {xgmii_tx_ctrl0_d3, xgmii_tx_byte0_d3} <= {xgmii_tx_ctrl0_d2, xgmii_tx_byte0_d2};
end

///////////////////////////////////////
// re-align byte lanes
// get original ipg from incoming streaming data, including preamble 64'hfb555555555555d5
reg [31:0] xgmii_tx_ipg_cnt;
always @(posedge xgmii_rx_clk or posedge rst) begin
  if (rst)
    xgmii_tx_ipg_cnt <= 'd0;
  else if (int_tx_vld && int_tx_sop)
    xgmii_tx_ipg_cnt <= 'd0;
  else if (int_tx_vld && int_tx_eop)
    xgmii_tx_ipg_cnt <= 'd8 - ((int_tx_mod==3'd0)? 'd8: int_tx_mod);
  else if (!int_tx_vld)
    xgmii_tx_ipg_cnt <= xgmii_tx_ipg_cnt + 'd8;
end
// bypass the 1st packet
reg xgmii_tx_ipg_1st;
always @(posedge xgmii_rx_clk or posedge rst) begin
  if (rst)
    xgmii_tx_ipg_1st <= 1'b0;
  else if (int_tx_vld && int_tx_sop)
    xgmii_tx_ipg_1st <= 1'b1;
end
// get ipg_diff_acc
reg         xgmii_tx_align_lane4;
reg  [31:0] xgmii_tx_ipg_diff_acc;
wire [31:0] xgmii_tx_ipg_diff_acc_curr = xgmii_tx_ipg_diff_acc + xgmii_tx_ipg_cnt;
always @(posedge xgmii_rx_clk or posedge rst) begin
  if (rst)
    xgmii_tx_ipg_diff_acc <= 'd0;
  else if (xgmii_tx_ipg_1st && (int_tx_vld && int_tx_sop))
    if (xgmii_tx_ipg_diff_acc_curr < (12 + 8) || xgmii_tx_ipg_diff_acc_curr[31]==1'b1)
      xgmii_tx_ipg_diff_acc <= (xgmii_tx_ipg_diff_acc + xgmii_tx_ipg_cnt) - (12 + 8) + (xgmii_tx_align_lane4? 4: 0);
    else
      xgmii_tx_ipg_diff_acc <= 'd0;
end
// get alignment signal, based on ipg_diff_acc 
//always @(*) xgmii_tx_align_lane4 <= 1'b1;
always @(posedge xgmii_rx_clk or posedge rst) begin
  if (rst)
    xgmii_tx_align_lane4 <= 1'b0;
  else if (xgmii_tx_ipg_1st && (int_tx_vld_d1 && int_tx_sop_d1))
    if (xgmii_tx_ipg_diff_acc[31])
      xgmii_tx_align_lane4 <= 1'b1;
    else
      xgmii_tx_align_lane4 <= 1'b0;
end

///////////////////////////////////////
// RGMII Tx data output with alignment adjustment
always @(posedge xgmii_rx_clk or posedge rst) begin
  if (rst)
    xgmii_tx_dc <= 72'h83c1e0f0783c1e0f07;
  else
    if (!xgmii_tx_align_lane4)
      xgmii_tx_dc <= {xgmii_tx_ctrl7_d1, xgmii_tx_byte7_d1, xgmii_tx_ctrl6_d1, xgmii_tx_byte6_d1, 
                      xgmii_tx_ctrl5_d1, xgmii_tx_byte5_d1, xgmii_tx_ctrl4_d1, xgmii_tx_byte4_d1,
                      xgmii_tx_ctrl3_d1, xgmii_tx_byte3_d1, xgmii_tx_ctrl2_d1, xgmii_tx_byte2_d1,
                      xgmii_tx_ctrl1_d1, xgmii_tx_byte1_d1, xgmii_tx_ctrl0_d1, xgmii_tx_byte0_d1};
    else
      xgmii_tx_dc <= {xgmii_tx_ctrl3_d1, xgmii_tx_byte3_d1, xgmii_tx_ctrl2_d1, xgmii_tx_byte2_d1,
                      xgmii_tx_ctrl1_d1, xgmii_tx_byte1_d1, xgmii_tx_ctrl0_d1, xgmii_tx_byte0_d1,
                      xgmii_tx_ctrl7_d2, xgmii_tx_byte7_d2, xgmii_tx_ctrl6_d2, xgmii_tx_byte6_d2, 
                      xgmii_tx_ctrl5_d2, xgmii_tx_byte5_d2, xgmii_tx_ctrl4_d2, xgmii_tx_byte4_d2};
end

///////////////////////////////////////
// RGMII RX
///////////////////////////////////////

///////////////////////////////////////
// buffer interface signals
reg [71: 0] xgmii_rx_dc_d1, xgmii_rx_dc_d2, xgmii_rx_dc_d3, xgmii_rx_dc_d4;
always @(posedge xgmii_rx_clk or posedge rst) begin
  if (rst) begin
    xgmii_rx_dc_d1 <= 72'h83c1e0f0783c1e0f07;
    xgmii_rx_dc_d2 <= 72'h83c1e0f0783c1e0f07;
    xgmii_rx_dc_d3 <= 72'h83c1e0f0783c1e0f07;
    xgmii_rx_dc_d4 <= 72'h83c1e0f0783c1e0f07;
  end
  else begin
    xgmii_rx_dc_d1 <= xgmii_rx_dc;
    xgmii_rx_dc_d2 <= xgmii_rx_dc_d1;
    xgmii_rx_dc_d3 <= xgmii_rx_dc_d2;
    xgmii_rx_dc_d4 <= xgmii_rx_dc_d3;
  end
end

///////////////////////////////////////
// convert bus to lane
(* mark_debug = "true" *) wire       xgmii_rx_ctrl7 = xgmii_rx_dc_d1[   71];
(* mark_debug = "true" *) wire [7:0] xgmii_rx_byte7 = xgmii_rx_dc_d1[70:63];
(* mark_debug = "true" *) wire       xgmii_rx_ctrl6 = xgmii_rx_dc_d1[   62];
(* mark_debug = "true" *) wire [7:0] xgmii_rx_byte6 = xgmii_rx_dc_d1[61:54];
(* mark_debug = "true" *) wire       xgmii_rx_ctrl5 = xgmii_rx_dc_d1[   53];
(* mark_debug = "true" *) wire [7:0] xgmii_rx_byte5 = xgmii_rx_dc_d1[52:45];
(* mark_debug = "true" *) wire       xgmii_rx_ctrl4 = xgmii_rx_dc_d1[   44];
(* mark_debug = "true" *) wire [7:0] xgmii_rx_byte4 = xgmii_rx_dc_d1[43:36];

(* mark_debug = "true" *) wire       xgmii_rx_ctrl3 = xgmii_rx_dc_d1[   35];
(* mark_debug = "true" *) wire [7:0] xgmii_rx_byte3 = xgmii_rx_dc_d1[34:27];
(* mark_debug = "true" *) wire       xgmii_rx_ctrl2 = xgmii_rx_dc_d1[   26];
(* mark_debug = "true" *) wire [7:0] xgmii_rx_byte2 = xgmii_rx_dc_d1[25:18];
(* mark_debug = "true" *) wire       xgmii_rx_ctrl1 = xgmii_rx_dc_d1[   17];
(* mark_debug = "true" *) wire [7:0] xgmii_rx_byte1 = xgmii_rx_dc_d1[16: 9];
(* mark_debug = "true" *) wire       xgmii_rx_ctrl0 = xgmii_rx_dc_d1[    8];
(* mark_debug = "true" *) wire [7:0] xgmii_rx_byte0 = xgmii_rx_dc_d1[ 7: 0];

///////////////////////////////////////
// convert lane data to internal data
reg         int_rx_vld;
reg         int_rx_sop;
reg         int_rx_eop;
reg [ 2: 0] int_rx_mod;
reg [63: 0] int_rx_dat;
// get XGMII first cycle alignment
reg xgmii_rx_align_lane4;
always @(posedge xgmii_rx_clk or posedge rst) begin
  if (rst)
    xgmii_rx_align_lane4 <= 1'b0;
  else if ({xgmii_rx_ctrl4, xgmii_rx_byte4} == 9'h1fb) 
    xgmii_rx_align_lane4 <= 1'b1;
  else if ({xgmii_rx_ctrl0, xgmii_rx_byte0} == 9'h1fb)
    xgmii_rx_align_lane4 <= 1'b0;
end
// get realigned rx_ctrl
reg [ 7: 0] int_rx_ctrl;
always @(posedge xgmii_rx_clk or posedge rst) begin
  if (rst)
    int_rx_ctrl <= 8'hff;
  else if (!xgmii_rx_align_lane4)
    int_rx_ctrl <= {xgmii_rx_dc_d2[ 8], xgmii_rx_dc_d2[17], xgmii_rx_dc_d2[26], xgmii_rx_dc_d2[35],
                    xgmii_rx_dc_d2[44], xgmii_rx_dc_d2[53], xgmii_rx_dc_d2[62], xgmii_rx_dc_d2[71]};
  else
    int_rx_ctrl <= {xgmii_rx_dc_d2[44], xgmii_rx_dc_d2[53], xgmii_rx_dc_d2[62], xgmii_rx_dc_d2[71],
                    xgmii_rx_dc_d1[ 8], xgmii_rx_dc_d1[17], xgmii_rx_dc_d1[26], xgmii_rx_dc_d1[35]};
end
// get realigned rx_data
reg [63: 0] int_rx_data;
always @(posedge xgmii_rx_clk or posedge rst) begin
  if (rst)
    int_rx_data <= 64'd0;
  else if (!xgmii_rx_align_lane4)
    int_rx_data <= {xgmii_rx_dc_d2[ 7: 0], xgmii_rx_dc_d2[16: 9], xgmii_rx_dc_d2[25:18], xgmii_rx_dc_d2[34:27],
                    xgmii_rx_dc_d2[43:36], xgmii_rx_dc_d2[52:45], xgmii_rx_dc_d2[61:54], xgmii_rx_dc_d2[70:63]};
  else
    int_rx_data <= {xgmii_rx_dc_d2[43:36], xgmii_rx_dc_d2[52:45], xgmii_rx_dc_d2[61:54], xgmii_rx_dc_d2[70:63],
                    xgmii_rx_dc_d1[ 7: 0], xgmii_rx_dc_d1[16: 9], xgmii_rx_dc_d1[25:18], xgmii_rx_dc_d1[34:27]};
end

///////////////////////////////////////
// generate streaming data 
// delay rx_ctrl, rx_data
reg [ 7:0] int_rx_ctrl_d1, int_rx_ctrl_d2;
reg [63:0] int_rx_data_d1, int_rx_data_d2;
always @(posedge xgmii_rx_clk or posedge rst) begin
  if (rst) begin
    int_rx_ctrl_d1 <= 8'hff;
    int_rx_ctrl_d2 <= 8'hff;
    int_rx_data_d1 <= 64'h0707070707070707;
    int_rx_data_d2 <= 64'h0707070707070707;
  end
  else begin
    int_rx_ctrl_d1 <= int_rx_ctrl;
    int_rx_ctrl_d2 <= int_rx_ctrl_d1;
    int_rx_data_d1 <= int_rx_data;
    int_rx_data_d2 <= int_rx_data_d1;
  end
end
// determine end of packet
wire [7:0] int_rx_vld_0_mod;
assign int_rx_vld_0_mod[7] = ({int_rx_ctrl[7], int_rx_data[63:56]} == {1'b1, 8'hfd})? 1'b1: 1'b0;
assign int_rx_vld_0_mod[6] = ({int_rx_ctrl[6], int_rx_data[55:48]} == {1'b1, 8'hfd})? 1'b1: 1'b0;
assign int_rx_vld_0_mod[5] = ({int_rx_ctrl[5], int_rx_data[47:40]} == {1'b1, 8'hfd})? 1'b1: 1'b0;
assign int_rx_vld_0_mod[4] = ({int_rx_ctrl[4], int_rx_data[39:32]} == {1'b1, 8'hfd})? 1'b1: 1'b0;
assign int_rx_vld_0_mod[3] = ({int_rx_ctrl[3], int_rx_data[31:24]} == {1'b1, 8'hfd})? 1'b1: 1'b0;
assign int_rx_vld_0_mod[2] = ({int_rx_ctrl[2], int_rx_data[23:16]} == {1'b1, 8'hfd})? 1'b1: 1'b0;
assign int_rx_vld_0_mod[1] = ({int_rx_ctrl[1], int_rx_data[15: 8]} == {1'b1, 8'hfd})? 1'b1: 1'b0;
assign int_rx_vld_0_mod[0] = ({int_rx_ctrl[0], int_rx_data[ 7: 0]} == {1'b1, 8'hfd})? 1'b1: 1'b0;
reg  [7:0] int_rx_vld_0_mod_d1; always @(posedge xgmii_rx_clk) int_rx_vld_0_mod_d1 <= int_rx_vld_0_mod;
reg  [7:0] int_rx_vld_0_mod_d2; always @(posedge xgmii_rx_clk) int_rx_vld_0_mod_d2 <= int_rx_vld_0_mod_d1;
// get realigned rx_vld 
wire int_rx_vld_1    = ({int_rx_ctrl[7], int_rx_data[63:56]} == {1'b1, 8'hfb})? 1'b1: 1'b0;
wire int_rx_vld_0    = (int_rx_vld_0_mod != 8'h00)? 1'b1: 1'b0;
reg  int_rx_vld_1_d1; always @(posedge xgmii_rx_clk) int_rx_vld_1_d1 <= int_rx_vld_1;
reg  int_rx_vld_0_d1; always @(posedge xgmii_rx_clk) int_rx_vld_0_d1 <= int_rx_vld_0;
reg  int_rx_vld_1_d2; always @(posedge xgmii_rx_clk) int_rx_vld_1_d2 <= int_rx_vld_1_d1;
reg  int_rx_vld_0_d2; always @(posedge xgmii_rx_clk) int_rx_vld_0_d2 <= int_rx_vld_0_d1;
always @(posedge xgmii_rx_clk or posedge rst) begin
  if (rst)
    int_rx_vld <= 1'b0;
  else if (int_rx_vld_1_d2)
    int_rx_vld <= 1'b1;
  else if (int_rx_vld_0_mod_d2 != 8'h80 && int_rx_vld_0_d2)
      int_rx_vld <= 1'b0;
  else if (int_rx_vld_0_mod_d1 == 8'h80 && int_rx_vld_0_d1)
      int_rx_vld <= 1'b0;
end
// get realigned rx_sop
always @(posedge xgmii_rx_clk or posedge rst) begin
  if (rst)
    int_rx_sop <= 1'b0;
  else if (int_rx_sop)
    int_rx_sop <= 1'b0;
  else if (int_rx_vld_1_d2)
    int_rx_sop <= 1'b1;
end
// get realigned rx_eop
always @(posedge xgmii_rx_clk or posedge rst) begin
  if (rst)
    int_rx_eop <= 1'b0;
  else if (int_rx_eop)
    int_rx_eop <= 1'b0;
  else if (int_rx_vld_0_mod_d1 != 8'h80 && int_rx_vld_0_d1)
      int_rx_eop <= 1'b1;
  else if (int_rx_vld_0_mod    == 8'h80 && int_rx_vld_0)
      int_rx_eop <= 1'b1;
end
// get realigned rx_mod
always @(posedge xgmii_rx_clk or posedge rst) begin
  if (rst)
    int_rx_mod <= 3'd0;
  else if (int_rx_eop)
    int_rx_mod <= 3'd0;
  else if(int_rx_vld_0_mod_d1 != 8'h80 && int_rx_vld_0_d1)
    case (int_rx_vld_0_mod_d1)
      8'h01: int_rx_mod <= 3'd7;
      8'h02: int_rx_mod <= 3'd6;
      8'h04: int_rx_mod <= 3'd5;
      8'h08: int_rx_mod <= 3'd4;
      8'h10: int_rx_mod <= 3'd3;
      8'h20: int_rx_mod <= 3'd2;
      8'h40: int_rx_mod <= 3'd1;
    endcase
  else if (int_rx_vld_0_mod    == 8'h80 && int_rx_vld_0)
    int_rx_mod <= 3'd0;
end
// get realigned rx_dat
always @(posedge xgmii_rx_clk or posedge rst) begin
  if (rst)
    int_rx_dat <= 64'd0;
  else
    int_rx_dat <= int_rx_data_d1;
end

///////////////////////////////////////
// output to local streaming interface
always @(posedge xgmii_rx_clk or posedge rst) begin
  if (rst) begin
    rx_vld <=  1'b0;
    rx_sop <=  1'b0;
    rx_eop <=  1'b0;
    rx_mod <=  3'd0;
    rx_dat <= 64'd0;
  end
  else begin
    rx_vld <= int_rx_vld;
    rx_sop <= int_rx_sop;
    rx_eop <= int_rx_eop;
    rx_mod <= int_rx_mod;
    rx_dat <= int_rx_dat;
  end
end

endmodule
